package com.jibei.mendo.service;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import com.blankj.utilcode.util.SPUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.cosofteck.gpiodemo.GpioControl;
import com.jibei.mendo.MendoApplication;
import com.jibei.mendo.activity.MainActivity;
import com.jibei.mendo.activity.SettingActivity;
import com.jibei.mendo.bean.ConfigInfoBean;
import com.jibei.mendo.bean.IgnitionInfoBean;
import com.jibei.mendo.event.Event;
import com.jibei.mendo.utils.ClientUtil;
import com.jibei.mendo.utils.Constant;
import com.jibei.mendo.utils.EventBusUtil;
import com.jibei.mendo.utils.SendCommandUtil;
import com.jibei.mendo.utils.SerialPortUtil;
import com.jibei.mendo.utils.ServerUtil;
import com.jibei.mendo.utils.ThreadPoolUtils;
import com.jibei.mendo.utils.TimeCodeSerial;
import com.jibei.mendo.utils.TimeUtil;
import com.jibei.mendo.utils.ToastUtil;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

/**
 * Created by Devin on 2019/8/11.
 * MENDO的后台服务类
 */
public class MendoService extends Service {

    private boolean isDianHuoRotateKey = false;
    private boolean isKongDangRotateKey = false;
    private boolean isJianCeRotateKey = false;
    public AtomicInteger continue_counter = new AtomicInteger();
    private boolean isReadyPressKey = false;
    private boolean isDianHuoPressKey = false;

    private CountDownTimer countDownTotalTimer;//总燃放倒计时
    private CountDownTimer countDownItemTimer;//距离下次燃放倒计时

    private final MendoBinder binder = new MendoBinder();

    public MendoService() {
    }

    public class MendoBinder extends Binder {
        public MendoService getService() {
            return MendoService.this;
        }
    }

    @SuppressLint("CheckResult")
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        EventBusUtil.getInstance().register(this);
        Observable.timer(2000, TimeUnit.MILLISECONDS)
                .subscribe(aLong -> {
                    checkRotateKeyStatus();
                    checkPressKeyStatus();
                    SerialPortUtil.getInstance().serialPortStartRead();
                    TimeCodeSerial.getInstance().serialPortStartRead();
                    protectProcess();
                });
        Log.d("lhl", "   MendoService   >>>   onBind");
        return binder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        countDownTotalTimer.cancel();
        countDownItemTimer.cancel();
        EventBusUtil.getInstance().unregister(this);
        Log.d("lhl", "   MendoService   >>>onUnbind");
        return super.onUnbind(intent);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public boolean onServiceReceiveEvents(Event event) {
        //Log.i("lhl", "MendoService接收到了EventBus数据");
        boolean isCaptured = true;
        switch (event.getTag()) {
            case Constant.Events.ROLE_FROM_EXCEL:
                break;
            default:
                isCaptured = false;
                break;
        }
        return isCaptured;
    }

    /**
     * 开启线程去查询旋转按钮的状态
     * 有如下的状态：点火；空挡；检测
     */
    public void checkRotateKeyStatus() {
        setGpioDirection(Constant.PG.PG12, 0);//设置PG12为输入状态
        setGpioDirection(Constant.PG.PG13, 0);//设置PG13为输入状态
        ThreadPoolUtils.execute(() -> {
            try {
                while (true) {
                    int nValue204 = GpioControl.readGpioValue(Constant.PG.PG12);  //读取PG12的输入电平
                    int nValue205 = GpioControl.readGpioValue(Constant.PG.PG13);  //读取PG13的输入电平

                    if (nValue204 == 0 && nValue205 == 1 && !isDianHuoRotateKey) {
                        isKongDangRotateKey = false;
                        isJianCeRotateKey = false;
                        isDianHuoRotateKey = true;
                        Log.d("lhl", "continue_counter in checkRoteKeyStatus:" + continue_counter);
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.DIAN_HUO, continue_counter));
                        Log.i("lhl", "   旋转按钮当前为   >>>点火");//点火
                    }
                    if (nValue204 == 1 && nValue205 == 0 && !isJianCeRotateKey) {
                        isKongDangRotateKey = false;
                        isJianCeRotateKey = true;
                        isDianHuoRotateKey = false;
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.JIAN_CE));
                        Log.i("lhl", "   旋转按钮当前为   >>>检测");//检测
                    }
                    if (nValue205 == 1 && nValue204 == 1 && !isKongDangRotateKey) {
                        isKongDangRotateKey = true;
                        isJianCeRotateKey = false;
                        isDianHuoRotateKey = false;
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.KONG_DANG));
                        Log.i("lhl", "   旋转按钮当前为   >>>空挡");//空挡
                    }

                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 开启线程查询按压键的状态
     * 有如下按压键：预备；点火等（包括但不限于此）
     */
    @SuppressLint("CheckResult")
    public void checkPressKeyStatus() {
        setGpioDirection(Constant.PG.PG1, 0);//设置PG1为输入状态
        setGpioDirection(Constant.PG.PG3, 0);//设置PG3为输入状态
        ThreadPoolUtils.execute(() -> {
            try {
                while (true) {
                    boolean isClientRec = false;
                    int nValue195 = GpioControl.readGpioValue(Constant.PG.PG3);  //读取PG3的输入电平
                    int nValue193 = GpioControl.readGpioValue(Constant.PG.PG1);  //读取PG1的输入电平
                    int StoredRole = SPUtils.getInstance().getInt(Constant.MASTERSLAVER,1);
                    int StoreCurrent = SPUtils.getInstance().getInt(Constant.CURRENTITEM,4);
                    //预备按钮
                    if (nValue195 == 0 && !isReadyPressKey && isDianHuoRotateKey && !SPUtils.getInstance().getBoolean("protect_process", false)) {
                        isReadyPressKey = true;
                        readyLEDFlicker(100);
                        Log.d("lhl", "wodemayaeee: ");
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.READY_PRESS));

                        //发送ready指令
                        sendReadyCommand();
                        //onReadyLED();
                        isReadyPressKey = false;
                        Log.i("lhl", "   按压按钮的当前状态   >>>ready");//预备
                    }
                    if ((StoredRole == 2 && StoreCurrent==4)) {
                        try {
                            isClientRec = MainActivity.isClientReFire;
                        }
                        catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    //点火按钮
                    if ((nValue193 == 0 && !isDianHuoPressKey && isDianHuoRotateKey && !SPUtils.getInstance().getBoolean("protect_process", false))
                            || (TimeCodeSerial.getInstance().recinfottyS3.contains("START") && isDianHuoRotateKey)
                            || isClientRec&&isDianHuoRotateKey) {
                        Log.d(Constant.TAG,"成功进入点火循环");
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.POSTFIRECMD,"FireRED"));
                        try {
                            if ((StoredRole == 1 && StoreCurrent ==4)) {
//                                if(MainActivity.isServer2ClientSuccess)
//                                ServerUtil.getInstance().sendServerMessage("Fire");
//                                else{
//                                    ToastUtils.showLong("网络点火: 请检查网络配置");
//                                }
                                SettingActivity.broadcast_send("FireSecurity",Constant.SERVER_PORT);//广播点火消息
                                Log.d(Constant.TAG,"作为服务器：发送加密点火消息");
                            }

                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                            ToastUtils.showShort("网络错误");
                        }
                        isDianHuoPressKey = true;
                        TimeCodeSerial.Fire_music = false;
                        dianHuoLEDFlicker(100);//开启点火LED闪烁
                        EventBusUtil.getInstance().postEvent(new Event(Constant.Events.DIAN_HUO_PRESS));
                        continue_counter = sendCountDownTimer();
                        Log.d("lhl", "continue_counter int checkPressKeyStates:" + continue_counter);
                        sendDianHuoCommand();
                        sendReleaseCommand(continue_counter);
                        isDianHuoPressKey = false;
                        Log.i("lhl", "   按压按钮的当前状态   >>>dian huo");//点火
                    }
                    Thread.sleep(10);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 发送ready指令
     */
    private void sendReadyCommand() {
        List<ConfigInfoBean> configInfoBeanList = MendoApplication.getApplication().getDaoSession().getConfigInfoBeanDao().queryBuilder().list();
        if (configInfoBeanList != null && configInfoBeanList.size() > 0) {
            SendCommandUtil.getInstance().sendReadyCommand(configInfoBeanList);
        } else {
            ToastUtils.showShort("ready指令集为空，请检查是否更新Excel文件!");
        }
    }

    private Disposable totalDisposable;
    private Disposable itemDisposable;
    int globle_index, recovery_index;

    /**
     * 开启倒计时
     */

    @SuppressLint("CheckResult")
    private AtomicInteger sendCountDownTimer() {
        AtomicInteger result = new AtomicInteger();
        ThreadPoolUtils.execute(() -> {
            List<IgnitionInfoBean> ignitionInfoBeanList = MendoApplication.getApplication().getDaoSession().getIgnitionInfoBeanDao().queryBuilder().list();
            if (ignitionInfoBeanList != null && ignitionInfoBeanList.size() > 0) {
                try {
                    //开启总燃放倒计时

                    long recoveryTime, continueTime, totalTime;
                    if (recovery_index != (ignitionInfoBeanList.size() - 1) && recovery_index != 0) {
                        globle_index = recovery_index;

                        recoveryTime = TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(globle_index).getTime());
                        totalTime = TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(ignitionInfoBeanList.size() - 1).getTime());
                        continueTime = totalTime - recoveryTime;

                        Log.d("lhl", "got recovery_index value = " + globle_index);
                    } else {
                        globle_index = 0;
                        continueTime = TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(ignitionInfoBeanList.size() - 1).getTime());
                    }

                    //long finalContinueTime = continueTime;
                    totalDisposable = Observable.just(0)
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(integer -> {
                                countDownTotalTimer(continueTime, 10);
                            });
                    for (int i = globle_index; i < ignitionInfoBeanList.size(); i++) {
                        long difTime = 0;

                        if ((GpioControl.readGpioValue(Constant.PG.PG12) == 1 && GpioControl.readGpioValue(Constant.PG.PG13) == 1)
                                || (TimeCodeSerial.getInstance().recinfottyS3.contains("STOP"))) {
                            totalDisposable = Observable.just(0)
                                    .observeOn(AndroidSchedulers.mainThread())
                                    .subscribe(integer -> {
                                        countDownTotalTimer.cancel();
                                    });
                            recovery_index = i;
                            result.set(i);
                            EventBusUtil.getInstance().postEvent(new Event(Constant.Events.UPDATE_DIANHUO_INIT_VIEW, recovery_index));
                            Log.d("lhl", "hi you in fire cmd pause ! index recovery = " + result);
                            break;
                        }

                        if (i == 0) {
                            difTime = TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(0).getTime());
                        } else {
                            difTime = TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(i).getTime()) - TimeUtil.getInstance().timeToMillisecond(ignitionInfoBeanList.get(i - 1).getTime());//差值
                        }
                        //Log.i("lhl", "   时间差值为>>>" + difTime);
                        //开启距离下次燃放倒计时
                        long finalDifTime = difTime;
                        itemDisposable = Observable.just(0)
                                .observeOn(AndroidSchedulers.mainThread())
                                .subscribe(integer -> {
                                    countDownItemTimer(finalDifTime, 10);
                                });
                        recovery_index = i;
                        result.set(0);
                        //Thread.sleep(difTime);//暂不采取这种sleep的方式
                        isCountDownItemOver = true;
                        while (isCountDownItemOver) {
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return result;
    }

    /**
     * 发送点火命令
     */
    private void sendDianHuoCommand() {
        List<IgnitionInfoBean> ignitionInfoBeanList = MendoApplication.getApplication().getDaoSession().getIgnitionInfoBeanDao().queryBuilder().list();
        if (ignitionInfoBeanList != null && ignitionInfoBeanList.size() > 0) {
            SendCommandUtil.getInstance().sendDianHuoCommand(ignitionInfoBeanList);
        } else {
            ToastUtils.showShort("点火指令集为空，请检查是否更新Excel文件!");
        }
    }

    /**
     * 发送释放的命令
     */
    private void sendReleaseCommand(AtomicInteger isBreak) {
        //无返回值情况下释放电能:
        try {
            SendCommandUtil.getInstance().sendAllReleaseCommandWithNoRe();
            Thread.sleep(100);
            SendCommandUtil.getInstance().sendAllReleaseCommandWithNoRe();
            Thread.sleep(500);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (isBreak.get() == 0) {
            Log.d("lhl", "检测到持续燃放完成，发送无返回值释放命令成功");
            EventBusUtil.getInstance().postEvent(new Event(Constant.Events.UPDATEUI));
            GpioControl.writeGpioDirection(Constant.PG.PG9, 1);//设置PG9为输出状态
            GpioControl.writeGpioValue(Constant.PG.PG9, 0);//拉低PG9
        } else
            Log.d("lhl", "检测到暂停 总线继续供电");
        //        List<ConfigInfoBean> configInfoBeanList = MendoApplication.getApplication().getDaoSession().getConfigInfoBeanDao().queryBuilder().list();
        //        if (configInfoBeanList != null && configInfoBeanList.size() > 0) {
        //            SendCommandUtil.getInstance().sendReleaseCommand(configInfoBeanList);
        //        }
    }

    /**
     * 预备LED灯的闪烁
     */
    private void readyLEDFlicker(long delayTime) {
        ThreadPoolUtils.execute(() -> {
            try {
                setGpioDirection(Constant.PG.PG4, 1);//设置预备LED为输出状态
                while (isReadyPressKey) {
                    onReadyLED();
                    Thread.sleep(delayTime);
                    offReadyLED();
                    Thread.sleep(delayTime);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 预备的LED灯亮
     */
    private void onReadyLED() {
        GpioControl.writeGpioValue(Constant.PG.PG4, 1);//预备LED灯亮
    }

    /**
     * 预备的LED灯灭
     */
    private void offReadyLED() {
        GpioControl.writeGpioValue(Constant.PG.PG4, 0);//预备LED灯灭
    }

    /**
     * 点火LED灯的闪烁
     */
    private void dianHuoLEDFlicker(long delayTime) {
        ThreadPoolUtils.execute(() -> {
            try {
                setGpioDirection(Constant.PG.PG5, 1);//设置点火LED为输出状态
                while (isDianHuoPressKey) {
                    onDianHuoLED();
                    Thread.sleep(delayTime);
                    offDianHuoLED();
                    Thread.sleep(delayTime);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 点火的LED灯亮
     */
    private void onDianHuoLED() {
        GpioControl.writeGpioValue(Constant.PG.PG5, 1);//点火LED灯亮
    }

    /**
     * 点火的LED灯灭
     */
    private void offDianHuoLED() {
        GpioControl.writeGpioValue(Constant.PG.PG5, 0);//点火LED灯灭
    }

    /**
     * 设置gpio某个口的输入输出状态
     *
     * @param num
     * @param value
     */
    private void setGpioDirection(int num, int value) {
        GpioControl.writeGpioDirection(num, value);
    }

    /**
     * 总燃放倒计时
     *
     * @param totalMillisTime    总倒计时时间
     * @param intervalMillisTime 间隔的时间
     */
    private void countDownTotalTimer(long totalMillisTime, long intervalMillisTime) {
        countDownTotalTimer = new CountDownTimer(totalMillisTime, intervalMillisTime) {
            @Override
            public void onTick(long l) {
                mOnTotalTimerCountDownListener.onTotalTick(l);
            }

            @Override
            public void onFinish() {
                mOnTotalTimerCountDownListener.onTotalFinish();
                if (totalDisposable != null) {
                    totalDisposable.dispose();
                }
                totalDisposable = null;
                countDownTotalTimer.cancel();
            }
        }.start();
    }

    private boolean isCountDownItemOver = true;

    /**
     * 距离下次燃放倒计时
     *
     * @param totalMillisTime    总倒计时时间
     * @param intervalMillisTime 间隔的时间
     */
    private void countDownItemTimer(long totalMillisTime, long intervalMillisTime) {
        countDownItemTimer = new CountDownTimer(totalMillisTime, intervalMillisTime) {
            @Override
            public void onTick(long l) {
                mOnItemTimerCountDownListener.onItemTick(l);
            }

            @Override
            public void onFinish() {
                mOnItemTimerCountDownListener.onItemFinish();
                isCountDownItemOver = false;
                if (itemDisposable != null) {
                    itemDisposable.dispose();
                }
                itemDisposable = null;
                countDownItemTimer.cancel();
            }
        }.start();
    }

    private static OnTotalTimerCountDownListener mOnTotalTimerCountDownListener;
    private static OnItemTimerCountDownListener mOnItemTimerCountDownListener;

    public static void setOnTimerCountDownListener(OnTotalTimerCountDownListener mOnTotalTimerCountDownListener, OnItemTimerCountDownListener mOnItemTimerCountDownListener) {
        MendoService.mOnTotalTimerCountDownListener = mOnTotalTimerCountDownListener;
        MendoService.mOnItemTimerCountDownListener = mOnItemTimerCountDownListener;
    }

    public interface OnTotalTimerCountDownListener {

        void onTotalTick(long l);

        void onTotalFinish();
    }

    public interface OnItemTimerCountDownListener {
        void onItemTick(long l);

        void onItemFinish();
    }

    @SuppressLint("CheckResult")
    private void protectProcess() {
        Observable.timer(1, TimeUnit.DAYS)
                .subscribe(aLong -> {
                    SPUtils.getInstance().put("protect_process", true);
                    mOnProtectProcessListener.onProtectProcessListener();
                });
    }

    public interface OnProtectProcessListener {
        void onProtectProcessListener();
    }

    private static OnProtectProcessListener mOnProtectProcessListener;

    public static void setOnProtectProcessListener(OnProtectProcessListener mOnProtectProcessListener) {
        MendoService.mOnProtectProcessListener = mOnProtectProcessListener;
    }

}